// Decompiled with JetBrains decompiler
// Type: Communication.CommunicationManager
// Assembly: FMCommon, Version=1.0.8663.21262, Culture=neutral, PublicKeyToken=null
// MVID: 52773074-FB09-4BA0-8FA9-4782D11D6C17
// Assembly location: /Users/mac/work/RiverGame/com.rivergame.fmframework/Runtime/Plugins/FMCommon.dll

using System;
using System.Collections.Generic;

namespace Communication
{
  public class CommunicationManager
  {
    private Queue<IRequestPacket> sendingPacketQueue = new Queue<IRequestPacket>();
    private int _perFrameSendNumLimited = 5;
    private float _perFrameProcessTimeLimited = 0.03333333f;
    public const int DEFAULT_PER_FRAME_MAX_SEND_TIME = 5;
    public const float DEFAULT_PER_FRAME_MAX_PROCESS_TIME = 0.03333333f;
    private IChannel socketClient;
    private ICommunicationMessageFactory messageFactory;
    private ICommunicationMessageHandlerRegistry messageHandlerRegistry;
    private int frameSendTimes;
    private ICommunicationMessageBroadcaster _messageBroadcaster;
    public Func<string, object, string, bool> messageInterceptor;

    public CommunicationManager(
      IChannel channel,
      ICommunicationMessageFactory messageFactory,
      ICommunicationMessageHandlerRegistry messageHandlerRegistry,
      ICommunicationMessageBroadcaster broadcaster,
      float perFrameProcessTimeLimited = 0.03333333f,
      int perFrameSendNumLimited = 5)
    {
      this.messageFactory = messageFactory;
      this.messageHandlerRegistry = messageHandlerRegistry ?? (ICommunicationMessageHandlerRegistry) new BaseCommunicationMessageHandlerRegistry();
      this.socketClient = channel;
      this._messageBroadcaster = broadcaster;
      this._perFrameProcessTimeLimited = perFrameProcessTimeLimited;
      this._perFrameSendNumLimited = perFrameSendNumLimited;
      if (this._perFrameSendNumLimited >= 0)
        return;
      this._perFrameSendNumLimited = int.MaxValue;
    }

    public void TryConnect()
    {
      this.sendingPacketQueue.Clear();
      this.socketClient.TryConnect();
    }

    public IRequestPacket SendMessage(object message)
    {
      IRequestPacket requestMessage = this.messageFactory.CreateRequestMessage(message);
      if (this.frameSendTimes < this._perFrameSendNumLimited && this.sendingPacketQueue.Count == 0)
      {
        ++this.frameSendTimes;
        this.DoSend(requestMessage);
      }
      else
        this.sendingPacketQueue.Enqueue(requestMessage);
      return requestMessage;
    }

    public void DebugUpdate(bool skipReceiveMessage, bool forceReceiveAll = false)
    {
      if (!skipReceiveMessage)
        this.socketClient.HandleReceiveMsgs();
      this.DoUpdate(forceReceiveAll);
    }

    public void Update(bool forceReceiveAll = false)
    {
      this.socketClient.HandleReceiveMsgs();
      this.DoUpdate(forceReceiveAll);
    }

    private void DoUpdate(bool forceReceiveAll = false)
    {
      double elapsedSeconds = RealTimer.elapsedSeconds;
      var response = (IResponsePacket)this.socketClient.PopHandleMsg();
      do {
        if (response!=null)
        {
          string messageSignature = response.GetMessageSignature();
          object data = response.GetData();
          string uniqueId = response.GetUniqueId();
          long responseTime = response.GetResponseTime();
          this.messageFactory.RecycleResponseMessage(response);
          if (this.messageInterceptor == null || !this.messageInterceptor(messageSignature, data, uniqueId))
          {
            ICommunicationMessageHandler messageHandler = this.messageHandlerRegistry.GetMessageHandler(messageSignature);
            if (messageHandler != null)
              messageHandler.HandleMessage(data, responseTime);
            else if (this._messageBroadcaster != null)
              this._messageBroadcaster.Broadcast(messageSignature, data);
          }
        }
      }
      while (response != null && RealTimer.elapsedSeconds - elapsedSeconds <= (double) this._perFrameProcessTimeLimited | forceReceiveAll);
      this.frameSendTimes = 0;
      while (this.sendingPacketQueue.Count > 0 && this.frameSendTimes < this._perFrameSendNumLimited)
      {
        ++this.frameSendTimes;
        this.DoSend(this.sendingPacketQueue.Dequeue());
      }
      if (this.frameSendTimes < this._perFrameSendNumLimited)
        return;
      this.frameSendTimes = 0;
    }

    public void DispatchMessage(string signature, object message, string uniqueId = null)
    {
      if (this.messageInterceptor != null && this.messageInterceptor(signature, message, uniqueId))
        return;
      ICommunicationMessageHandler messageHandler = this.messageHandlerRegistry.GetMessageHandler(signature);
      if (messageHandler != null)
      {
        messageHandler.HandleMessage(message, RealTimer.elapsedMilliseconds);
      }
      else
      {
        if (this._messageBroadcaster == null)
          return;
        this._messageBroadcaster.Broadcast(signature, message);
      }
    }

    public void RegistMessageHandler(string signature, ICommunicationMessageHandler handler)
    {
      this.messageHandlerRegistry.RegistMessageHandler(signature, handler);
    }

    public void RegistMessageHandler(string signature, AbstractCommunicationMessageHandler handler)
    {
      this.messageHandlerRegistry.RegistMessageHandler(signature, (ICommunicationMessageHandler) handler);
      handler.SetCommunicationManager(this);
    }

    public void UnRegistMessageHandler(string signature)
    {
      this.messageHandlerRegistry.UnRegistMessageHandler(signature);
    }

    public void UnRegistMessageHandler(
      string signature,
      AbstractCommunicationMessageHandler handler)
    {
      handler.SetCommunicationManager((CommunicationManager) null);
      this.messageHandlerRegistry.UnRegistMessageHandler(signature);
    }

    public void Reset()
    {
      this.messageHandlerRegistry.Reset();
    }

    private void DoSend(IRequestPacket request)
    {
      this.socketClient.SendMessage(request.GetData());
      this.messageFactory.RecycleRequestMessage(request);
    }

    private enum COMMUNICATION_STATUS
    {
      SENDING,
      READY_TO_SEND,
    }
  }
}
